package rad.framework.uml2.presentation;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EventObject;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.command.BasicCommandStack;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.command.CommandStack;
import org.eclipse.emf.common.command.CommandStackListener;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.ui.ViewerPane;
import org.eclipse.emf.common.ui.viewer.IViewerProvider;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EValidator;
import org.eclipse.emf.ecore.provider.EcoreItemProviderAdapterFactory;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.domain.IEditingDomainProvider;
import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
import org.eclipse.emf.edit.ui.action.EditingDomainActionBarContributor;
import org.eclipse.emf.edit.ui.celleditor.AdapterFactoryTreeEditor;
import org.eclipse.emf.edit.ui.dnd.EditingDomainViewerDropAdapter;
import org.eclipse.emf.edit.ui.dnd.LocalTransfer;
import org.eclipse.emf.edit.ui.dnd.ViewerDragAdapter;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.emf.edit.ui.view.ExtendedPropertySheetPage;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.dialogs.SaveAsDialog;
import org.eclipse.ui.ide.IGotoMarker;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.views.contentoutline.ContentOutline;
import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.PropertySheet;
import org.eclipse.ui.views.properties.PropertySheetPage;

import rad.framework.uml2.uml.edit.providers.UMLItemProviderAdapterFactory;


/**
 * Ceci est un editeur d'un modele UML2;
 * 
 * @author boudyacho
 */
public class UML2Editor extends MultiPageEditorPart implements IEditingDomainProvider, ISelectionProvider, IMenuListener, IViewerProvider, IGotoMarker {

	public static final String copyright = "";

	protected AdapterFactoryEditingDomain editingDomain;

	protected ComposedAdapterFactory adapterFactory;

	protected IContentOutlinePage contentOutlinePage;

	protected IStatusLineManager contentOutlineStatusLineManager;

	protected TreeViewer contentOutlineViewer;

	protected PropertySheetPage propertySheetPage;

	protected TreeViewer selectionViewer;

	protected TreeViewer parentViewer;

	protected TreeViewer treeViewer;

	protected ListViewer listViewer;

	protected TableViewer tableViewer;

	protected TreeViewer treeViewerWithColumns;

	protected ViewerPane currentViewerPane;

	protected Viewer currentViewer;

	protected ISelectionChangedListener selectionChangedListener;

	protected Collection selectionChangedListeners = new ArrayList();

	protected ISelection editorSelection = StructuredSelection.EMPTY;

	protected IPartListener partListener = new IPartListener() {
		public void partActivated(IWorkbenchPart p) {
			if (p instanceof ContentOutline) {
				if (((ContentOutline) p).getCurrentPage() == contentOutlinePage) {
					getActionBarContributor().setActiveEditor(UML2Editor.this);

					setCurrentViewer(contentOutlineViewer);
				}
			} else if (p instanceof PropertySheet) {
				if (((PropertySheet) p).getCurrentPage() == propertySheetPage) {
					getActionBarContributor().setActiveEditor(UML2Editor.this);
					handleActivate();
				}
			} else if (p == UML2Editor.this) {
				handleActivate();
			}
		}

		public void partBroughtToTop(IWorkbenchPart p) {
		}

		public void partClosed(IWorkbenchPart p) {
		}

		public void partDeactivated(IWorkbenchPart p) {
		}

		public void partOpened(IWorkbenchPart p) {
		}
	};

	Collection removedResources = new ArrayList();

	Collection changedResources = new ArrayList();

	Collection savedResources = new ArrayList();

	protected IResourceChangeListener resourceChangeListener = new IResourceChangeListener() {
		public void resourceChanged(IResourceChangeEvent event) {

			{
				final IResourceDelta delta = event.getDelta();
				try {
					class ResourceDeltaVisitor implements IResourceDeltaVisitor {
						protected ResourceSet resourceSet = editingDomain.getResourceSet();
						protected Collection changedResources = new ArrayList();
						protected Collection removedResources = new ArrayList();

						public boolean visit(IResourceDelta delta) {
							if (delta.getFlags() != IResourceDelta.MARKERS && delta.getResource().getType() == IResource.FILE) {
								if ((delta.getKind() & (IResourceDelta.CHANGED | IResourceDelta.REMOVED)) != 0) {
									final Resource resource = resourceSet.getResource(URI.createURI(delta.getFullPath().toString()), false);
									if (resource != null) {
										if ((delta.getKind() & IResourceDelta.REMOVED) != 0) {
											removedResources.add(resource);
										} else {
											changedResources.add(resource);
										}
									}
								}
							}

							return true;
						}

						public Collection getChangedResources() {
							return changedResources;
						}

						public Collection getRemovedResources() {
							return removedResources;
						}
					}

					final ResourceDeltaVisitor visitor = new ResourceDeltaVisitor();
					delta.accept(visitor);

					if (!visitor.getRemovedResources().isEmpty()) {
						removedResources.addAll(visitor.getRemovedResources());
						if (!isDirty()) {
							getSite().getShell().getDisplay().asyncExec(new Runnable() {
								public void run() {
									getSite().getPage().closeEditor(UML2Editor.this, false);
									UML2Editor.this.dispose();
								}
							});
						}
					}

					if (!visitor.getChangedResources().isEmpty()) {
						changedResources.addAll(visitor.getChangedResources());
					}
				} catch (final CoreException exception) {
					UML2EditorPlugin.INSTANCE.log(exception);
				}
			}
		}
	};

	protected void handleActivate() {

		if (editingDomain.getResourceToReadOnlyMap() != null) {
			editingDomain.getResourceToReadOnlyMap().clear();

			setSelection(getSelection());
		}

		if (!removedResources.isEmpty()) {
			if (handleDirtyConflict()) {
				getSite().getPage().closeEditor(UML2Editor.this, false);
				UML2Editor.this.dispose();
			} else {
				removedResources.clear();
				changedResources.clear();
				savedResources.clear();
			}
		} else if (!changedResources.isEmpty()) {
			changedResources.removeAll(savedResources);
			handleChangedResources();
			changedResources.clear();
			savedResources.clear();
		}
	}

	protected void handleChangedResources() {
		if (!changedResources.isEmpty() && (!isDirty() || handleDirtyConflict())) {
			editingDomain.getCommandStack().flush();

			for (final Iterator i = changedResources.iterator(); i.hasNext();) {
				final Resource resource = (Resource) i.next();
				if (resource.isLoaded()) {
					resource.unload();
					try {
						resource.load(Collections.EMPTY_MAP);
					} catch (final IOException exception) {
						UML2EditorPlugin.INSTANCE.log(exception);
					}
				}
			}
		}
	}

	protected boolean handleDirtyConflict() {
		return MessageDialog.openQuestion(getSite().getShell(), UML2Editor.getString("_UI_FileConflict_label"), UML2Editor.getString("_WARN_FileConflict"));
	}

	public UML2Editor() {
		super();

		final List factories = new ArrayList();
		factories.add(new ResourceItemProviderAdapterFactory());
		factories.add(new UMLItemProviderAdapterFactory());
		factories.add(new EcoreItemProviderAdapterFactory());
		factories.add(new ReflectiveItemProviderAdapterFactory());

		adapterFactory = new ComposedAdapterFactory(factories);

		final BasicCommandStack commandStack = new BasicCommandStack();

		commandStack.addCommandStackListener(new CommandStackListener() {
			public void commandStackChanged(final EventObject event) {
				getContainer().getDisplay().asyncExec(new Runnable() {
					public void run() {
						firePropertyChange(IEditorPart.PROP_DIRTY);

						final Command mostRecentCommand = ((CommandStack) event.getSource()).getMostRecentCommand();
						if (mostRecentCommand != null) {
							setSelectionToViewer(mostRecentCommand.getAffectedObjects());
						}
						if (propertySheetPage != null) {
							propertySheetPage.refresh();
						}
					}
				});
			}
		});

		editingDomain = new AdapterFactoryEditingDomain(adapterFactory, commandStack, new HashMap());
	}

	@Override
	protected void firePropertyChange(int action) {
		super.firePropertyChange(action);
	}

	public void setSelectionToViewer(Collection collection) {
		final Collection theSelection = collection;

		if (theSelection != null && !theSelection.isEmpty()) {

			final Runnable runnable = new Runnable() {
				public void run() {

					if (currentViewer != null) {
						currentViewer.setSelection(new StructuredSelection(theSelection.toArray()), true);
					}
				}
			};
			runnable.run();
		}
	}

	public EditingDomain getEditingDomain() {
		return editingDomain;
	}

	public class ReverseAdapterFactoryContentProvider extends AdapterFactoryContentProvider {
		public ReverseAdapterFactoryContentProvider(AdapterFactory adapterFactory) {
			super(adapterFactory);
		}

		@Override
		public Object[] getElements(Object object) {
			final Object parent = super.getParent(object);
			return (parent == null ? Collections.EMPTY_SET : Collections.singleton(parent)).toArray();
		}

		@Override
		public Object[] getChildren(Object object) {
			final Object parent = super.getParent(object);
			return (parent == null ? Collections.EMPTY_SET : Collections.singleton(parent)).toArray();
		}

		@Override
		public boolean hasChildren(Object object) {
			final Object parent = super.getParent(object);
			return parent != null;
		}

		@Override
		public Object getParent(Object object) {
			return null;
		}
	}

	public void setCurrentViewerPane(ViewerPane viewerPane) {
		if (currentViewerPane != viewerPane) {
			if (currentViewerPane != null) {
				currentViewerPane.showFocus(false);
			}
			currentViewerPane = viewerPane;
		}
		setCurrentViewer(currentViewerPane.getViewer());
	}

	public void setCurrentViewer(Viewer viewer) {

		if (currentViewer != viewer) {
			if (selectionChangedListener == null) {

				selectionChangedListener = new ISelectionChangedListener() {

					public void selectionChanged(SelectionChangedEvent selectionChangedEvent) {
						setSelection(selectionChangedEvent.getSelection());
					}
				};
			}

			if (currentViewer != null) {
				currentViewer.removeSelectionChangedListener(selectionChangedListener);
			}

			if (viewer != null) {
				viewer.addSelectionChangedListener(selectionChangedListener);
			}

			currentViewer = viewer;

			setSelection(currentViewer == null ? StructuredSelection.EMPTY : currentViewer.getSelection());
		}
	}

	public Viewer getViewer() {
		return currentViewer;
	}

	protected void createContextMenuFor(StructuredViewer viewer) {
		final MenuManager contextMenu = new MenuManager("#PopUp");
		contextMenu.add(new Separator("additions"));
		contextMenu.setRemoveAllWhenShown(true);
		contextMenu.addMenuListener(this);
		final Menu menu = contextMenu.createContextMenu(viewer.getControl());
		viewer.getControl().setMenu(menu);
		getSite().registerContextMenu(contextMenu, viewer);

		final int dndOperations = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
		final Transfer[] transfers = new Transfer[] {
			LocalTransfer.getInstance()
		};
		viewer.addDragSupport(dndOperations, transfers, new ViewerDragAdapter(viewer));
		viewer.addDropSupport(dndOperations, transfers, new EditingDomainViewerDropAdapter(editingDomain, viewer));
	}

	public void createModel() {

		final IFileEditorInput modelFile = (IFileEditorInput) getEditorInput();

		try {

			editingDomain.loadResource(URI.createPlatformResourceURI(modelFile.getFile().getFullPath().toString()).toString());
		} catch (final Exception exception) {
			UML2EditorPlugin.INSTANCE.log(exception);
		}
	}

	@Override
	public void createPages() {

		createModel();

		{
			final ViewerPane viewerPane = new ViewerPane(getSite().getPage(), UML2Editor.this) {
				@Override
				public Viewer createViewer(Composite composite) {
					final Tree tree = new Tree(composite, SWT.MULTI);
					final TreeViewer newTreeViewer = new TreeViewer(tree);
					return newTreeViewer;
				}

				@Override
				public void requestActivation() {
					super.requestActivation();
					setCurrentViewerPane(this);
				}
			};
			viewerPane.createControl(getContainer());

			selectionViewer = (TreeViewer) viewerPane.getViewer();
			selectionViewer.setContentProvider(new AdapterFactoryContentProvider(adapterFactory));

			selectionViewer.setLabelProvider(new AdapterFactoryLabelProvider(adapterFactory));
			selectionViewer.setInput(editingDomain.getResourceSet());
			viewerPane.setTitle(editingDomain.getResourceSet());

			new AdapterFactoryTreeEditor(selectionViewer.getTree(), adapterFactory);

			createContextMenuFor(selectionViewer);
			final int pageIndex = addPage(viewerPane.getControl());
			setPageText(pageIndex, UML2Editor.getString("_UI_SelectionPage_label"));
		}

		{
			final ViewerPane viewerPane = new ViewerPane(getSite().getPage(), UML2Editor.this) {
				@Override
				public Viewer createViewer(Composite composite) {
					final Tree tree = new Tree(composite, SWT.MULTI);
					final TreeViewer newTreeViewer = new TreeViewer(tree);
					return newTreeViewer;
				}

				@Override
				public void requestActivation() {
					super.requestActivation();
					setCurrentViewerPane(this);
				}
			};
			viewerPane.createControl(getContainer());

			parentViewer = (TreeViewer) viewerPane.getViewer();
			parentViewer.setAutoExpandLevel(30);
			parentViewer.setContentProvider(new ReverseAdapterFactoryContentProvider(adapterFactory));
			parentViewer.setLabelProvider(new AdapterFactoryLabelProvider(adapterFactory));

			createContextMenuFor(parentViewer);
			final int pageIndex = addPage(viewerPane.getControl());
			setPageText(pageIndex, UML2Editor.getString("_UI_ParentPage_label"));
		}

		{
			final ViewerPane viewerPane = new ViewerPane(getSite().getPage(), UML2Editor.this) {
				@Override
				public Viewer createViewer(Composite composite) {
					return new ListViewer(composite);
				}

				@Override
				public void requestActivation() {
					super.requestActivation();
					setCurrentViewerPane(this);
				}
			};
			viewerPane.createControl(getContainer());
			listViewer = (ListViewer) viewerPane.getViewer();
			listViewer.setContentProvider(new AdapterFactoryContentProvider(adapterFactory));
			listViewer.setLabelProvider(new AdapterFactoryLabelProvider(adapterFactory));

			createContextMenuFor(listViewer);
			final int pageIndex = addPage(viewerPane.getControl());
			setPageText(pageIndex, UML2Editor.getString("_UI_ListPage_label"));
		}

		{
			final ViewerPane viewerPane = new ViewerPane(getSite().getPage(), UML2Editor.this) {
				@Override
				public Viewer createViewer(Composite composite) {
					return new TreeViewer(composite);
				}

				@Override
				public void requestActivation() {
					super.requestActivation();
					setCurrentViewerPane(this);
				}
			};
			viewerPane.createControl(getContainer());
			treeViewer = (TreeViewer) viewerPane.getViewer();
			treeViewer.setContentProvider(new AdapterFactoryContentProvider(adapterFactory));
			treeViewer.setLabelProvider(new AdapterFactoryLabelProvider(adapterFactory));

			new AdapterFactoryTreeEditor(treeViewer.getTree(), adapterFactory);

			createContextMenuFor(treeViewer);
			final int pageIndex = addPage(viewerPane.getControl());
			setPageText(pageIndex, UML2Editor.getString("_UI_TreePage_label"));
		}

		{
			final ViewerPane viewerPane = new ViewerPane(getSite().getPage(), UML2Editor.this) {
				@Override
				public Viewer createViewer(Composite composite) {
					return new TableViewer(composite);
				}

				@Override
				public void requestActivation() {
					super.requestActivation();
					setCurrentViewerPane(this);
				}
			};
			viewerPane.createControl(getContainer());
			tableViewer = (TableViewer) viewerPane.getViewer();

			final Table table = tableViewer.getTable();
			final TableLayout layout = new TableLayout();
			table.setLayout(layout);
			table.setHeaderVisible(true);
			table.setLinesVisible(true);

			final TableColumn objectColumn = new TableColumn(table, SWT.NONE);
			layout.addColumnData(new ColumnWeightData(3, 100, true));
			objectColumn.setText(UML2Editor.getString("_UI_ObjectColumn_label"));
			objectColumn.setResizable(true);

			final TableColumn selfColumn = new TableColumn(table, SWT.NONE);
			layout.addColumnData(new ColumnWeightData(2, 100, true));
			selfColumn.setText(UML2Editor.getString("_UI_SelfColumn_label"));
			selfColumn.setResizable(true);

			tableViewer.setColumnProperties(new String[] {
					"a", "b"
			});
			tableViewer.setContentProvider(new AdapterFactoryContentProvider(adapterFactory));
			tableViewer.setLabelProvider(new AdapterFactoryLabelProvider(adapterFactory));

			createContextMenuFor(tableViewer);
			final int pageIndex = addPage(viewerPane.getControl());
			setPageText(pageIndex, UML2Editor.getString("_UI_TablePage_label"));
		}

		{
			final ViewerPane viewerPane = new ViewerPane(getSite().getPage(), UML2Editor.this) {
				@Override
				public Viewer createViewer(Composite composite) {
					return new TreeViewer(composite);
				}

				@Override
				public void requestActivation() {
					super.requestActivation();
					setCurrentViewerPane(this);
				}
			};
			viewerPane.createControl(getContainer());

			treeViewerWithColumns = (TreeViewer) viewerPane.getViewer();

			final Tree tree = treeViewerWithColumns.getTree();
			tree.setLayoutData(new FillLayout());
			tree.setHeaderVisible(true);
			tree.setLinesVisible(true);

			final TreeColumn objectColumn = new TreeColumn(tree, SWT.NONE);
			objectColumn.setText(UML2Editor.getString("_UI_ObjectColumn_label"));
			objectColumn.setResizable(true);
			objectColumn.setWidth(250);

			final TreeColumn selfColumn = new TreeColumn(tree, SWT.NONE);
			selfColumn.setText(UML2Editor.getString("_UI_SelfColumn_label"));
			selfColumn.setResizable(true);
			selfColumn.setWidth(200);

			treeViewerWithColumns.setColumnProperties(new String[] {
					"a", "b"
			});
			treeViewerWithColumns.setContentProvider(new AdapterFactoryContentProvider(adapterFactory));
			treeViewerWithColumns.setLabelProvider(new AdapterFactoryLabelProvider(adapterFactory));

			createContextMenuFor(treeViewerWithColumns);
			final int pageIndex = addPage(viewerPane.getControl());
			setPageText(pageIndex, UML2Editor.getString("_UI_TreeWithColumnsPage_label"));
		}

		setActivePage(0);

		getContainer().addControlListener(new ControlAdapter() {
			boolean guard = false;

			@Override
			public void controlResized(ControlEvent event) {
				if (!guard) {
					guard = true;
					hideTabs();
					guard = false;
				}
			}
		});
	}

	protected void hideTabs() {
		if (getPageCount() <= 1) {
			setPageText(0, "");
			if (getContainer() instanceof CTabFolder) {
				((CTabFolder) getContainer()).setTabHeight(1);
				final Point point = getContainer().getSize();
				getContainer().setSize(point.x, point.y + 6);
			}
		}
	}

	@Override
	protected void pageChange(int pageIndex) {
		super.pageChange(pageIndex);

		if (contentOutlinePage != null) {
			handleContentOutlineSelection(contentOutlinePage.getSelection());
		}
	}

	@Override
	public Object getAdapter(Class key) {
		if (key.equals(IContentOutlinePage.class)) {
			return getContentOutlinePage();
		} else if (key.equals(IPropertySheetPage.class)) {
			return getPropertySheetPage();
		} else if (key.equals(IGotoMarker.class)) {
			return this;
		} else {
			return super.getAdapter(key);
		}
	}

	public IContentOutlinePage getContentOutlinePage() {
		if (contentOutlinePage == null) {

			class MyContentOutlinePage extends ContentOutlinePage {
				@Override
				public void createControl(Composite parent) {
					super.createControl(parent);
					contentOutlineViewer = getTreeViewer();
					contentOutlineViewer.addSelectionChangedListener(this);

					contentOutlineViewer.setContentProvider(new AdapterFactoryContentProvider(adapterFactory));
					contentOutlineViewer.setLabelProvider(new AdapterFactoryLabelProvider(adapterFactory));
					contentOutlineViewer.setInput(editingDomain.getResourceSet());

					createContextMenuFor(contentOutlineViewer);

					if (!editingDomain.getResourceSet().getResources().isEmpty()) {

						final ArrayList selection = new ArrayList();
						selection.add(editingDomain.getResourceSet().getResources().get(0));
						contentOutlineViewer.setSelection(new StructuredSelection(selection), true);
					}
				}

				@Override
				public void makeContributions(IMenuManager menuManager, IToolBarManager toolBarManager, IStatusLineManager statusLineManager) {
					super.makeContributions(menuManager, toolBarManager, statusLineManager);
					contentOutlineStatusLineManager = statusLineManager;
				}

				@Override
				public void setActionBars(IActionBars actionBars) {
					super.setActionBars(actionBars);
					getActionBarContributor().shareGlobalActions(this, actionBars);
				}
			}

			contentOutlinePage = new MyContentOutlinePage();

			contentOutlinePage.addSelectionChangedListener(new ISelectionChangedListener() {

				public void selectionChanged(SelectionChangedEvent event) {
					handleContentOutlineSelection(event.getSelection());
				}
			});
		}

		return contentOutlinePage;
	}

	public IPropertySheetPage getPropertySheetPage() {
		if (propertySheetPage == null) {
			propertySheetPage = new ExtendedPropertySheetPage(editingDomain) {
				@Override
				public void setSelectionToViewer(List selection) {
					UML2Editor.this.setSelectionToViewer(selection);
					UML2Editor.this.setFocus();
				}

				@Override
				public void setActionBars(IActionBars actionBars) {
					super.setActionBars(actionBars);
					getActionBarContributor().shareGlobalActions(this, actionBars);
				}
			};
			propertySheetPage.setPropertySourceProvider(new AdapterFactoryContentProvider(adapterFactory));
		}

		return propertySheetPage;
	}

	public void handleContentOutlineSelection(ISelection selection) {
		if (currentViewerPane != null && !selection.isEmpty() && selection instanceof IStructuredSelection) {
			final Iterator selectedElements = ((IStructuredSelection) selection).iterator();
			if (selectedElements.hasNext()) {

				final Object selectedElement = selectedElements.next();

				if (currentViewerPane.getViewer() == selectionViewer) {
					final ArrayList selectionList = new ArrayList();
					selectionList.add(selectedElement);
					while (selectedElements.hasNext()) {
						selectionList.add(selectedElements.next());
					}

					selectionViewer.setSelection(new StructuredSelection(selectionList));
				} else {

					if (currentViewerPane.getViewer().getInput() != selectedElement) {
						currentViewerPane.getViewer().setInput(selectedElement);
						currentViewerPane.setTitle(selectedElement);
					}
				}
			}
		}
	}

	@Override
	public boolean isDirty() {
		return ((BasicCommandStack) editingDomain.getCommandStack()).isSaveNeeded();
	}

	@Override
	public void doSave(IProgressMonitor progressMonitor) {

		final WorkspaceModifyOperation operation = new WorkspaceModifyOperation() {

			@Override
			public void execute(IProgressMonitor monitor) {
				try {

					final Resource savedResource = editingDomain.getResourceSet().getResources().get(0);
					savedResources.add(savedResource);
					savedResource.save(Collections.EMPTY_MAP);
				} catch (final Exception exception) {
					UML2EditorPlugin.INSTANCE.log(exception);
				}
			}
		};

		try {

			new ProgressMonitorDialog(getSite().getShell()).run(true, false, operation);

			((BasicCommandStack) editingDomain.getCommandStack()).saveIsDone();
			firePropertyChange(IEditorPart.PROP_DIRTY);
		} catch (final Exception exception) {

			UML2EditorPlugin.INSTANCE.log(exception);
		}
	}

	@Override
	public boolean isSaveAsAllowed() {
		return true;
	}

	@Override
	public void doSaveAs() {
		final SaveAsDialog saveAsDialog = new SaveAsDialog(getSite().getShell());
		saveAsDialog.open();
		final IPath path = saveAsDialog.getResult();
		if (path != null) {
			final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
			if (file != null) {
				doSaveAs(URI.createPlatformResourceURI(file.getFullPath().toString()), new FileEditorInput(file));
			}
		}
	}

	protected void doSaveAs(URI uri, IEditorInput editorInput) {
		editingDomain.getResourceSet().getResources().get(0).setURI(uri);
		setInputWithNotify(editorInput);
		setPartName(editorInput.getName());
		final IProgressMonitor progressMonitor = getActionBars().getStatusLineManager() != null ? getActionBars().getStatusLineManager().getProgressMonitor() : new NullProgressMonitor();
		doSave(progressMonitor);
	}

	public void gotoMarker(IMarker marker) {
		try {
			if (marker.getType().equals(EValidator.MARKER)) {
				final String uriAttribute = marker.getAttribute(EValidator.URI_ATTRIBUTE, null);
				if (uriAttribute != null) {
					final URI uri = URI.createURI(uriAttribute);
					final EObject eObject = editingDomain.getResourceSet().getEObject(uri, true);
					if (eObject != null) {
						setSelectionToViewer(Collections.singleton(editingDomain.getWrapper(eObject)));
					}
				}
			}
		} catch (final CoreException exception) {
			UML2EditorPlugin.INSTANCE.log(exception);
		}
	}

	@Override
	public void init(IEditorSite site, IEditorInput editorInput) {
		setSite(site);
		setInputWithNotify(editorInput);
		setPartName(editorInput.getName());
		site.setSelectionProvider(this);
		site.getPage().addPartListener(partListener);
		ResourcesPlugin.getWorkspace().addResourceChangeListener(resourceChangeListener, IResourceChangeEvent.POST_CHANGE);
	}

	@Override
	public void setFocus() {
		if (currentViewerPane != null) {
			currentViewerPane.setFocus();
		} else {
			getControl(getActivePage()).setFocus();
		}
	}

	public void addSelectionChangedListener(ISelectionChangedListener listener) {
		selectionChangedListeners.add(listener);
	}

	public void removeSelectionChangedListener(ISelectionChangedListener listener) {
		selectionChangedListeners.remove(listener);
	}

	public ISelection getSelection() {
		return editorSelection;
	}

	public void setSelection(ISelection selection) {
		editorSelection = selection;

		for (final Iterator listeners = selectionChangedListeners.iterator(); listeners.hasNext();) {
			final ISelectionChangedListener listener = (ISelectionChangedListener) listeners.next();
			listener.selectionChanged(new SelectionChangedEvent(this, selection));
		}
		setStatusLineManager(selection);
	}

	public void setStatusLineManager(ISelection selection) {
		final IStatusLineManager statusLineManager = currentViewer != null && currentViewer == contentOutlineViewer ? contentOutlineStatusLineManager : getActionBars().getStatusLineManager();

		if (statusLineManager != null) {
			if (selection instanceof IStructuredSelection) {
				final Collection collection = ((IStructuredSelection) selection).toList();
				switch (collection.size()) {
					case 0: {
						statusLineManager.setMessage(UML2Editor.getString("_UI_NoObjectSelected"));
						break;
					}
					case 1: {
						final String text = new AdapterFactoryItemDelegator(adapterFactory).getText(collection.iterator().next());
						statusLineManager.setMessage(UML2Editor.getString("_UI_SingleObjectSelected", text));
						break;
					}
					default: {
						statusLineManager.setMessage(UML2Editor.getString("_UI_MultiObjectSelected", Integer.toString(collection.size())));
						break;
					}
				}
			} else {
				statusLineManager.setMessage("");
			}
		}
	}

	private static String getString(String key) {
		return UML2EditorPlugin.INSTANCE.getString(key);
	}

	private static String getString(String key, Object s1) {
		return UML2EditorPlugin.INSTANCE.getString(key, new Object[] {
			s1
		});
	}

	public void menuAboutToShow(IMenuManager menuManager) {
		((IMenuListener) getEditorSite().getActionBarContributor()).menuAboutToShow(menuManager);
	}

	public EditingDomainActionBarContributor getActionBarContributor() {
		return (EditingDomainActionBarContributor) getEditorSite().getActionBarContributor();
	}

	public IActionBars getActionBars() {
		return getActionBarContributor().getActionBars();
	}

	public AdapterFactory getAdapterFactory() {
		return adapterFactory;
	}

	@Override
	public void dispose() {
		ResourcesPlugin.getWorkspace().removeResourceChangeListener(resourceChangeListener);

		getSite().getPage().removePartListener(partListener);

		adapterFactory.dispose();

		if (getActionBarContributor().getActiveEditor() == this) {
			getActionBarContributor().setActiveEditor(null);
		}

		if (propertySheetPage != null) {
			propertySheetPage.dispose();
		}

		if (contentOutlinePage != null) {
			contentOutlinePage.dispose();
		}

		super.dispose();
	}

}
